﻿using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;

namespace Devonline.AspNetCore;

public static class QueryableExtensions
{
    /// <summary>
    /// 返回 IQueryable 的条件 Where 查询
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="queryable"></param>
    /// <param name="condition"></param>
    /// <param name="predicate"></param>
    /// <returns></returns>
    public static IQueryable<T> WhereIf<T>(this IQueryable<T> queryable, bool condition, Expression<Func<T, bool>> predicate) => condition ? queryable.Where(predicate) : queryable;

    /// <summary>
    /// 返回分页查询的结果
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="queryable"></param>
    /// <param name="orderBy"></param>
    /// <param name="pageIndex"></param>
    /// <param name="pageSize"></param>
    /// <param name="isAsc"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    public static IQueryable<T> PageBy<T, TKey>(this IQueryable<T> queryable, Expression<Func<T, TKey>> orderBy, int pageIndex = AppSettings.DEFAULT_PAGE_INDEX, int pageSize = AppSettings.DEFAULT_PAGE_SIZE, bool isAsc = true)
    {
        if (queryable == null)
        {
            throw new ArgumentNullException(nameof(queryable));
        }

        // Check if the page number is greater then zero - otherwise use default page number
        if (pageIndex <= 0)
        {
            pageIndex = AppSettings.DEFAULT_PAGE_INDEX;
        }

        if (pageSize <= 0)
        {
            pageSize = AppSettings.DEFAULT_PAGE_SIZE;
        }

        // It is necessary sort items before it
        queryable = isAsc ? queryable.OrderBy(orderBy) : queryable.OrderByDescending(orderBy);
        return queryable.Skip((pageIndex - 1) * pageSize).Take(pageSize);
    }

    /// <summary>
    /// 返回分页查询的结果
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TKey"></typeparam>
    /// <param name="queryable"></param>
    /// <param name="pagedRequest"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    public static async Task<PagedResult<T>> PageByAsync<T>(this IQueryable<T> queryable, PagedQueryRequest pagedRequest)
    {
        if (queryable == null)
        {
            throw new ArgumentNullException(nameof(queryable));
        }

        if (!string.IsNullOrWhiteSpace(pagedRequest.OrderBy))
        {
            queryable = queryable.OrderBy(pagedRequest.OrderBy);
        }

        var result = new PagedResult<T>
        {
            Total = await queryable.CountAsync()
        };

        if (pagedRequest.PageIndex <= 0)
        {
            pagedRequest.PageIndex = AppSettings.DEFAULT_PAGE_INDEX;
        }

        if (pagedRequest.PageSize <= 0)
        {
            pagedRequest.PageSize = AppSettings.DEFAULT_PAGE_SIZE;
        }

        queryable = queryable.Skip((pagedRequest.PageIndex - 1) * pagedRequest.PageSize).Take(pagedRequest.PageSize);
        result.Rows = await queryable.ToListAsync();

        return result;
    }
}